﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Comp_GeoData;

namespace Comp_Geo
{
    public class Triangulator
    {
        private List<LineSegment> mapLines;
        private List<Node> nodes;

        public Triangulator(List<LineSegment> mapLines, Vector2 monsterPosition, Vector2 kittenPosition)
        {
            this.mapLines = mapLines;

            List<Node> adjacentNodes;
            nodes = new List<Node>();



            // Loop throught list of map lines and off set nodes by 1 x and 1 y
            // This will cause errors if the lines are too tight, but being magnitudes of 100s it should cause minimanl complicaitons
            foreach (LineSegment lineSegment in mapLines)
            {
                #region Old Code
                //Vector2 v;
                //if (lineSegment.StartPoint.X == lineSegment.EndPoint.X)
                //{
                //    if (lineSegment.StartPoint.Y < lineSegment.EndPoint.Y)
                //    {
                //        v = new Vector2(lineSegment.StartPoint.X - 1, lineSegment.StartPoint.Y + 1);
                //    }
                //    else
                //    {
                //        v = new Vector2(lineSegment.StartPoint.X + 1, lineSegment.StartPoint.Y - 1);
                //    }
                //}
                //else
                //{
                //    if (lineSegment.StartPoint.X < lineSegment.EndPoint.X)
                //    {
                //        v = new Vector2(lineSegment.StartPoint.X + 1, lineSegment.StartPoint.Y + 1);
                //    }
                //    else
                //    {
                //        v = new Vector2(lineSegment.StartPoint.X - 1, lineSegment.StartPoint.Y - 1);
                //    }
                //}

                //nodes.Add(new Node(v));
                #endregion
                nodes.Add(new Node(lineSegment.OffsetStartPoint));
            }

            // Set the next node in the list, which will corrospond to the end point, to the first node in the adjacent list
            foreach (Node node in nodes)
            {
                adjacentNodes = new List<Node>();
                if (nodes.IndexOf(node) == 0) // If first node in the list
                {
                    adjacentNodes.Add(nodes[nodes.Count - 1]); // The last node in the list
                    adjacentNodes.Add(nodes[1]);
                }
                else if (nodes.IndexOf(node) == (nodes.Count - 1)) // Last node in the list
                {
                    adjacentNodes.Add(nodes[nodes.Count - 2]); // The second to last node
                    adjacentNodes.Add(nodes[0]); // The first node
                }
                else // Otherwise the node is in the middle of the list
                {
                    adjacentNodes.Add(nodes[nodes.IndexOf(node) - 1]); // The previous node
                    adjacentNodes.Add(nodes[nodes.IndexOf(node) + 1]); // The next node
                }

                node.AdjacentNodes = adjacentNodes;
            }

            nodes.Add(new Node(monsterPosition, null));
            nodes.Add(new Node(kittenPosition, null));

            #region Old Code
            //// Sets up the 
            //foreach(LineSegment lineSegment in mapLines)
            //{
            //    foreach(Node node in nodes)
            //    {
            //        if(lineSegment.StartPoint == node.Position)
            //        {
            //            foreach(Node node2 in nodes)
            //            {
            //                if(lineSegment.EndPoint == node2.Position)
            //                {
            //                    adjacentNodes = new List<Node>();
            //                    adjacentNodes.Add(node2);
            //                    node.AdjacentNodes = adjacentNodes;
            //                }
            //            }
            //        }
            //    }
            //}
            #endregion
        }

        public Graph Triangulate()
        {
            Graph graph;
            bool collides;
            bool getOut=false;

            foreach (Node node in nodes)
            {

                foreach (Node node2 in nodes)
                {
                    collides = false;

                    if (node.Position == node2.Position)
                    {
                        continue;
                    }

                    // OMG this is really ugly, find a way to fix it in the future!
                    if (node.AdjacentNodes != null)
                    {
                        foreach (Node adjNode in node.AdjacentNodes)
                        {
                            if (adjNode.Position == node2.Position)
                                getOut = true;
                        }
                    }
                    if (getOut == true)
                    {
                        getOut = false;
                        continue;
                    }

                    LineSegment testLine = new LineSegment(node.Position, node2.Position);
                    foreach (LineSegment lineSegment in mapLines)
                    {
                        if (LineIntersectsLine(lineSegment, testLine) == true)
                        {
                            collides = true;
                        }
                    }

                    if (collides == false)
                    {
                        if (node.AdjacentNodes != null)
                        {
                            node.AdjacentNodes.Add(node2);
                        }
                        else
                        {
                            node.AdjacentNodes = new List<Node>();
                            node.AdjacentNodes.Add(node2);
                        }
                    }
                }

                foreach (Node node3 in node.AdjacentNodes)
                {
                    if (nodes.IndexOf(node) == nodes.Count - 2)
                    {
                        Console.WriteLine("Monster Contains NodeIndex:{0}", nodes.IndexOf(node3));
                    }

                    else if (nodes.IndexOf(node) == nodes.Count - 1)
                    {
                        Console.WriteLine("Kitten Contains NodeIndex:{0}", nodes.IndexOf(node3));
                    }

                    else
                        Console.WriteLine("NodeIndex:{0} Contains NodeIndex:{1}", nodes.IndexOf(node), nodes.IndexOf(node3));
                }
            }

            graph = new Graph(nodes);

            return graph;
        }

        // Test if two line segments intersect
        // if they do return false
        private bool LineIntersectsLine(LineSegment lineSeg, LineSegment testLine)
        {
            Vector2 L1P1 = lineSeg.StartPoint;
            Vector2 L1P2 = lineSeg.EndPoint;
            Vector2 L2P1 = testLine.StartPoint;
            Vector2 L2P2 = testLine.EndPoint;

            float q = (L1P1.Y - L2P1.Y) * (L2P2.X - L2P1.X) - (L1P1.X - L2P1.X) * (L2P2.Y - L2P1.Y);
            float d = (L1P2.X - L1P1.X) * (L2P2.Y - L2P1.Y) - (L1P2.Y - L1P1.Y) * (L2P2.X - L2P1.X);

            if (d == 0)
            {
                return false;
            }

            float r = q / d;
            q = (L1P1.Y - L2P1.Y) * (L1P2.X - L1P1.X) - (L1P1.X - L2P1.X) * (L1P2.Y - L1P1.Y);
            float s = q / d;

            if (r < 0 || r > 1 || s < 0 || s > 1)
            {
                return false;
            }

            return true;
        }
    }
}